package com.bitcola.security.applications.biz;


import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.bitcola.security.applications.config.Constant;
import com.bitcola.security.applications.entity.P2pOrder;
import com.bitcola.security.applications.feign.IExchangeFeign;
import com.bitcola.security.applications.mapper.AllowSellMapper;
import com.bitcola.security.applications.mapper.ColaUserBalanceMapper;
import com.bitcola.security.applications.mapper.P2POrderMapper;
import com.bitcola.security.applications.util.Snowflake;
import com.bitcola.security.common.exception.LackBalanceException;
import com.bitcola.security.common.exception.ParamLimitException;
import lombok.experimental.Accessors;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import org.apache.ibatis.session.RowBounds;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class P2pBiz {

    @Autowired
    P2POrderMapper p2POrderMapper;
    @Autowired
    ColaUserBalanceMapper balanceMapper;
    @Resource
    IExchangeFeign exchangeFeign;
    Snowflake snowflake=new Snowflake();
    ConcurrentHashMap<String,Integer> map=new ConcurrentHashMap();


    @Autowired
    AllowSellMapper allowSellMapper;


    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public P2pOrder sell(String userId, BigDecimal amount){
        P2pOrder p2pOrder = new P2pOrder();

             BigDecimal price = getPrice();

             p2pOrder.setId(snowflake.nextIdStr());
             p2pOrder.setCoinCode("TSOL");
             p2pOrder.setDirection(Constant.SELL);
             p2pOrder.setSeller(userId);
             String secret = RandomStringUtils.randomAlphanumeric(8);
             p2pOrder.setSecret(secret);
             int tag = balanceMapper.reduceUserBanlance(userId, "TSOL", amount, null);
             if (tag == 0) throw new LackBalanceException("缺钱");
             balanceMapper.addUserFrozenBanlance(userId, "TSOL", amount, null);
             p2pOrder.setPrice(price);
             p2pOrder.setAmount(amount);
             p2pOrder.setStatus(Constant.PENDING);
             p2pOrder.setTime(new Date());
             p2POrderMapper.insert(p2pOrder);
              int i =allowSellMapper.addAmount(amount.negate(),userId+"TSOL");
              if(i==0) throw new ParamLimitException("");


        return p2pOrder;
    }
    @Transactional(isolation = Isolation.REPEATABLE_READ)

    public P2pOrder buy(String userId,String secret){
        var lock= map.getOrDefault(secret,1);
        map.put(secret,lock);

        P2pOrder p2pOrder = null;
        synchronized (lock) {

            Example example = new Example(P2pOrder.class);
            example.createCriteria().andEqualTo("secret", secret);
            var list = p2POrderMapper.selectByExample(example);
            if (list.size() > 0) p2pOrder = list.get(0);
            else return null;
            if (!p2pOrder.getStatus().equals(Constant.PENDING)) throw new ParamLimitException("订单已经完成或者取消");
            BigDecimal amount = p2pOrder.getPrice().multiply(p2pOrder.getAmount());
            int tag = balanceMapper.reduceUserBanlance(userId, "USDT", amount, null);
            if (tag == 0) throw new LackBalanceException("缺钱");
            p2pOrder.setBuyer(userId);
            p2pOrder.setFee(amount.multiply(BigDecimal.valueOf(0.2)));
            balanceMapper.addUserBanlance(p2pOrder.getSeller(), "USDT", amount.subtract(p2pOrder.getFee()), null);

            balanceMapper.reduceUserFrozenBanlance(p2pOrder.getSeller(), "TSOL", p2pOrder.getAmount(), null);
            balanceMapper.addUserBanlance(p2pOrder.getBuyer(), "TSOL", p2pOrder.getAmount(), null);

            p2pOrder.setStatus(Constant.FINISH);

            p2POrderMapper.updateByPrimaryKey(p2pOrder);
            allowSellMapper.addAmount(p2pOrder.getAmount().multiply(BigDecimal.valueOf(0.5d)),userId+"TSOL");
        }
        return p2pOrder;


    }

    public String cancelAll()
    {


        var all= p2POrderMapper.selectAll();
        all.forEach(x->{
            if(x.getStatus().equals(Constant.PENDING)) cancel(x.getId(),false);
        });
        return "ok";
    }

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public boolean cancel(String id,boolean addSell)
    {
        var lock= map.getOrDefault(id,1);
        map.put(id,lock);

        synchronized (lock) {
            P2pOrder p2pOrder = p2POrderMapper.selectByPrimaryKey(id);
            if (p2pOrder.getStatus().equals(Constant.PENDING)) {


                p2pOrder.setStatus(Constant.CANCEL);
                //退钱
                int tag = balanceMapper.addUserBanlance(p2pOrder.getSeller(), "TSOL", p2pOrder.getAmount(), null);
                balanceMapper.reduceUserFrozenBanlance(p2pOrder.getSeller(), "TSOL", p2pOrder.getAmount(), null);
                p2pOrder.setStatus(Constant.CANCEL);
                p2POrderMapper.updateByPrimaryKey(p2pOrder);
                if(addSell) allowSellMapper.addAmount(p2pOrder.getAmount(),p2pOrder.getSeller()+"TSOL");

                return true;
            }
        }
        return false;

    }

    public List<P2pOrder> query(String userId,String direction,int page,int size)
    {
        Example example=new Example(P2pOrder.class);
        var crit= example.createCriteria();
        if(direction.equals(Constant.BUY)){
            crit.andEqualTo("buyer",userId);;


        }else{
            crit.andEqualTo("seller",userId);
        }
        example.setOrderByClause("status desc ,time  desc");

        RowBounds rowBounds=new RowBounds((page-1)*size,size);

        return p2POrderMapper.selectByExampleAndRowBounds(example,rowBounds);
    }
    @Cached(expire = 20,cacheType = CacheType.LOCAL)

    public BigDecimal getPrice()
    {
        return (BigDecimal) exchangeFeign.getUsdPrice("TSOL").data;

    }




}
